#include "tcpserver.h"
#include "asynevent.h"
#include "ntdproto.h"
#include "ntdtime.h"

//static const char MESSAGE[] = "Hello, World!\n";

#define MOD_NUM 10

static void
listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sa, int socklen, void *user_data)
{
	(static_cast<TCPServer *>(user_data))->OnIncomingConnection(fd, sa, socklen);
}

static void conn_readcb(struct bufferevent *bev, void *user_data)
{
	(static_cast<TCPServer *>(user_data))->OnRead();
}
static void conn_writecb(struct bufferevent *bev, void *user_data)
{
	(static_cast<TCPServer *>(user_data))->OnWrite();
}

static void conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
	if (events & BEV_EVENT_EOF) {
		printf("Connection closed.\n");
		(static_cast<TCPServer *>(user_data))->OnClose();
	} else if (events & BEV_EVENT_ERROR) {
		printf("Got an error on the connection: %s\n",
			strerror(errno));/*XXX win32*/
		(static_cast<TCPServer *>(user_data))->OnError(errno);
	}
	/* None of the other events can happen here, since we haven't enabled
	* timeouts */
	//bufferevent_free(bev);
}



TCPServer::TCPServer()
{
	m_listener = NULL;
	m_bev = NULL;
}

TCPServer::~TCPServer()
{
	if( m_bev )
		bufferevent_free(m_bev);
	if( m_listener )
		evconnlistener_free(m_listener);
}

bool TCPServer::Listen(int port)
{
	struct sockaddr_in sin;
	SetSockAddr(sin, 0, port);

	m_listener = evconnlistener_new_bind(
		AsynEventFramework::Instance()->GetEventBase(), 
		listener_cb, 
		(void *)this,
		LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, 
		-1,
		(struct sockaddr*)&sin,
		sizeof(sin));

	if (!m_listener) {
		fprintf(stderr, "Could not create a listener!\n");
		return false;
	}

	return true;
}

void TCPServer::Stop()
{
	evconnlistener_free(m_listener);
}

void TCPServer::OnIncomingConnection(evutil_socket_t fd, struct sockaddr *sa, int socklen)
{
	struct event_base * base = AsynEventFramework::Instance()->GetEventBase();

	m_bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	if (!m_bev) {
		fprintf(stderr, "Error constructing bufferevent!");
		event_base_loopbreak(base);
		return;
	}
	bufferevent_setcb(m_bev, conn_readcb, conn_writecb, conn_eventcb, this);
	bufferevent_enable(m_bev, EV_WRITE|EV_READ);
	//bufferevent_disable(bev, EV_READ);

	//bufferevent_write(m_bev, MESSAGE, strlen(MESSAGE));
	OnRead();
}

void TCPServer::HandleProtoData(NtdProtoData * proto, void* pContext)
{
	//LOG4CPLUS_TRACE(g_logger," [server] - "<<proto->Desc());

	//return;
	//m_sm.Add(proto->GetPaketSize());

	//m_feedback.m_ptk_seq = proto->m_ptk_seq;
	if( proto->m_ptk_seq % MOD_NUM == 0){
		m_feedback.m_pkt_loss = 0;
		//m_feedback.m_recving_rate = m_sm.GetSpeed();//Bytes/sec
		m_feedback.m_timestamp_sending = proto->m_timestamp_sending;
		m_feedback.m_timestamp_recving = NtdTime::Instance()->GetCurrentTime_ms();

		struct evbuffer *output = bufferevent_get_output(m_bev);
		m_feedback.Encode(output);
	}
}

void TCPServer::OnRead()
{
	//bufferevent_write_buffer(m_bev, bufferevent_get_input(m_bev));
	
	//char buf[1024];
	//int n;
	//struct evbuffer *input = bufferevent_get_input(m_bev);
	//while ((n = evbuffer_remove(input, buf, sizeof(buf))) > 0) {
	//	fwrite(buf, 1, n, stdout);
	//}

	while(true){
		bool ret = NtdProtoParser::ParseProtocol(bufferevent_get_input(m_bev), NULL);
		if( ret == false ){
			return;
		}
	}
}

void TCPServer::OnClose()
{
	bufferevent_free(m_bev);
	m_bev = NULL;
}

void TCPServer::OnError(int err)
{
	bufferevent_free(m_bev);
	m_bev = NULL;
}

void TCPServer::OnWrite()
{
	//struct evbuffer *output = bufferevent_get_output(m_bev);
	//if (evbuffer_get_length(output) == 0) {
	//	printf("flushed answer\n");
	//	bufferevent_free(m_bev);
	//	m_bev = NULL;
	//}
}
